import { Layout } from '@/layout';

export const meta = {
  title:
    'I get hydration warning about data-mantine-color-scheme attribute, what does it mean?',
  description:
    'Learn how hydration works and how to fix warnings',
  slug: 'color-scheme-hydration-warning',
  category: 'common',
  tags: ['color-scheme', 'defaultColorScheme', 'forceColorScheme', 'Next.js', 'React Router'],
  created_at: 'January 11, 2025',
  last_updated_at: 'January 11, 2025',
};

export default Layout(meta);

## Example hydration warning

<ErrorMessage error="Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used. > -data-mantine-color-scheme='light'" />

Minimal Next.js code that has this warning (Next.js used as an example, the same logic can be applied to any other framework with server-side rendering):

```tsx
// app/layout.tsx
import { ColorSchemeScript, MantineProvider } from '@mantine/core';

export default function RootLayout({ children }: { children: any }) {
  return (
    <html lang="en">
      <head>
        <ColorSchemeScript />
        <link rel="shortcut icon" href="/favicon.svg" />
        <meta
          name="viewport"
          content="minimum-scale=1, initial-scale=1, width=device-width, user-scalable=no"
        />
      </head>
      <body>
        <MantineProvider>{children}</MantineProvider>
      </body>
    </html>
  );
}
```

## Why do I get hydration warning?

To fully understand this hydration warning, let's break it down how server-side rendering
works in React in general (Next.js, React Router, etc.):

1. User navigates to the page in the browser.
2. The server renders the page and sends html code to the client.
3. html code is parsed by the browser and rendered on the screen (at this point, JavaScript has not been executed yet, uses has only html code).
4. JavaScript code is loaded and executed on the client.
5. Hydration process starts: React compares server-rendered html with client-rendered html and tries to match them.
   If server-rendered html does not match client-rendered html, React will re-render the component on the client and
   show a warning in the console (like the one above).

Hydration mismatch error can happen in two cases:

1. Server-rendered html does not match client-rendered html
2. Some code is executed on the client before React hydration starts and changes the html generated by the server

In the example above, `ColorSchemeScript` component is used to change `data-mantine-color-scheme`
attribute on the `<html />` element before hydration, which causes the mismatch.
`ColorSchemeScript` component executes for following JavaScript code:

```tsx
try {
  var _colorScheme = window.localStorage.getItem("mantine-color-scheme-value");
  var colorScheme = _colorScheme === "light" || _colorScheme === "dark" || _colorScheme === "auto" ? _colorScheme : "light";
  var computedColorScheme = colorScheme !== "auto" ? colorScheme : window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
  document.documentElement.setAttribute("data-mantine-color-scheme", computedColorScheme);
} catch (e) {}
```

This code is executed on the client before React hydration starts, which changes the html generated by the server and causes the warning.

## How to fix hydration warning?

To fix the hydration warning, spread `mantineHtmlProps` on the `<html />` element:

```tsx
// app/layout.tsx
import { ColorSchemeScript, MantineProvider, mantineHtmlProps } from '@mantine/core';

export default function RootLayout({ children }: { children: any }) {
  return (
    <html lang="en" {...mantineHtmlProps}>
      <head>
        <ColorSchemeScript />
        <link rel="shortcut icon" href="/favicon.svg" />
        <meta
          name="viewport"
          content="minimum-scale=1, initial-scale=1, width=device-width, user-scalable=no"
        />
      </head>
      <body>
        <MantineProvider>{children}</MantineProvider>
      </body>
    </html>
  );
}
```

## What is mantineHtmlProps?

`mantineHtmlProps` is an object with just two properties:

```tsx
export const mantineHtmlProps = {
  suppressHydrationWarning: true,
  'data-mantine-color-scheme': 'light',
};
```

- `suppressHydrationWarning` is used to disable hydration warning for the `<html />` element
- `data-mantine-color-scheme` is used to set default color scheme for the app when JavaScript is disabled, it is overridden by `ColorSchemeScript` component on the client before hydration

## Does hydration warning indicate a problem?

No, in this case, hydration warning is expected and does not indicate a problem with the app:
`data-mantine-color-scheme` attribute is change before hydration to prevent flash of inaccurate color scheme.

## How suppressHydrationWarning works?

`suppressHydrationWarning` is a special attribute that React uses to suppress hydration warning for the specific element.
It does not disable hydration warning for the whole app, only for the element with this attribute
(usually `<html />` element only).
